from PySide6.QtCore import Signal, Qt, Slot
from PySide6.QtGui import QFontDatabase, QPalette
from PySide6.QtWidgets import QWidget, QTabWidget, QVBoxLayout, QLabel, QComboBox, QSpinBox, QDialog, \
    QDialogButtonBox, QHBoxLayout, QRadioButton, QGroupBox, QFormLayout, QLineEdit, QButtonGroup, QCheckBox, \
    QColorDialog, QPushButton, QSlider

from utils.config import Settings
from utils.log import logger


class SettingsWindow(QDialog):

    def __init__(self, app, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.app = app
        self.settings = Settings()

        self.setWindowTitle('设置')
        self.setGeometry(100, 100, 400, 300)

        # 创建一个选项卡窗口
        self.tabs = QTabWidget()
        self.tab_general = GeneralTab(self.app)
        self.tabs.addTab(self.tab_general, '常规')
        self.tab_appearance = AppearanceTab(self.app)
        self.tabs.addTab(self.tab_appearance, '外观')
        self.tab_tran_api = TransAPITab(self.app)
        self.tabs.addTab(self.tab_tran_api, '翻译 API')

        self.button_box = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok |
                                           QDialogButtonBox.StandardButton.Cancel |
                                           QDialogButtonBox.StandardButton.Apply)

        self.button_box.button(QDialogButtonBox.StandardButton.Ok).setText('确认')
        self.button_box.button(QDialogButtonBox.StandardButton.Ok).clicked.connect(self.ok_event)

        self.button_box.button(QDialogButtonBox.StandardButton.Cancel).setText('取消')
        self.button_box.button(QDialogButtonBox.StandardButton.Cancel).clicked.connect(self.cancel_event)

        self.button_box.button(QDialogButtonBox.StandardButton.Apply).setText('应用')
        self.button_box.button(QDialogButtonBox.StandardButton.Apply).clicked.connect(self.apply_event)

        vbox_layout = QVBoxLayout()
        vbox_layout.addWidget(self.tabs)
        vbox_layout.addWidget(self.button_box)

        self.setLayout(vbox_layout)

    def connect_slots(self):
        self.tab_general.connect_slots()
        self.tab_appearance.connect_slots()

    def ok_event(self):
        self.save_settings()
        self.close()

    def cancel_event(self):
        self.close()

    def apply_event(self):
        self.save_settings()

    def save_settings(self):
        self.tab_general.save_settings()
        self.tab_appearance.save_settings()
        self.tab_tran_api.save_settings()
        self.settings.write_config()


class GeneralTab(QWidget):
    set_trans = Signal(str, str)

    def __init__(self, app, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.app = app
        self.settings = Settings()

        # 最外层垂直布局
        vbox_layout = QVBoxLayout()

        # 翻译设置组
        group_box_trans = QGroupBox('翻译设置')

        # 组内表单布局
        form_layout = QFormLayout()

        self.cmb_trans_mode = QComboBox()
        self.cmb_trans_mode.addItems(['自动检测', '中英互译', '中日互译'])
        form_layout.addRow(QLabel('翻译模式'), self.cmb_trans_mode)

        self.cmb_trans_api = QComboBox()
        self.cmb_trans_api.addItems(['百度翻译', '有道智云'])
        form_layout.addRow(QLabel('翻译 API'), self.cmb_trans_api)

        group_box_trans.setLayout(form_layout)  # 应用表单布局
        vbox_layout.addWidget(group_box_trans)  # 添加翻译设置组到垂直布局中

        # 动画设置组
        group_box_anim = QGroupBox('动画设置')

        # 组内表单布局
        form_layout = QFormLayout()

        # TODO: 动画设置

        group_box_anim.setLayout(form_layout)  # 应用表单布局
        vbox_layout.addWidget(group_box_anim)  # 添加动画设置组到垂直布局中

        self.setLayout(vbox_layout)  # 应用垂直布局

        # 初始化
        self.trans_mode = self.settings.trans_mode
        self.trans_api = self.settings.trans_api

    def connect_slots(self):
        self.set_trans.connect(self.app.menu.set_trans_handler)

    def save_settings(self):
        self.settings.trans_mode = self.trans_mode
        self.settings.trans_api = self.trans_api
        self.set_trans.emit(self.trans_mode, self.trans_api)

    @property
    def trans_mode(self) -> str:
        trans_mode_text = self.cmb_trans_mode.currentText()
        trans_mode_query = {
            '自动检测': 'auto',
            '中英互译': 'zh_en',
            '中日互译': 'zh_jp',
        }
        trans_mode = self.settings.trans_mode

        try:
            trans_mode = trans_mode_query[trans_mode_text]
        except KeyError:
            logger.exception(f'Invalid trans mode text, trans_mode_text={trans_mode_text}')
        finally:
            return trans_mode

    @trans_mode.setter
    def trans_mode(self, value: str):
        trans_mode_query = {
            'auto': '自动检测',
            'zh_en': '中英互译',
            'zh_jp': '中日互译',
        }

        try:
            self.cmb_trans_mode.setCurrentText(trans_mode_query[value])
        except KeyError:
            logger.exception(f'Invalid trans mode, value={value}')

    @property
    def trans_api(self) -> str:
        trans_api_text = self.cmb_trans_api.currentText()
        trans_api_query = {
            '百度翻译': 'Baidu',
            '有道智云': 'Youdao',
        }
        trans_api = self.settings.trans_api

        try:
            trans_api = trans_api_query[trans_api_text]
        except KeyError:
            logger.exception(f'Invalid trans API, trans_api={trans_api_text}')
        finally:
            return trans_api

    @trans_api.setter
    def trans_api(self, value: str):
        trans_api_query = {
            'Baidu': '百度翻译',
            'Youdao': '有道智云',
        }

        try:
            self.cmb_trans_api.setCurrentText(trans_api_query[value])
        except KeyError:
            logger.exception(f'Invalid trans API, trans_api={value}')

    @Slot(str, str)
    def set_trans_handler(self, trans_mode, trans_api):
        logger.debug(f'Handle set_trans, trans_mode={trans_mode}, trans_api={trans_api}')
        self.trans_mode = trans_mode
        self.trans_api = trans_api


class AppearanceTab(QWidget):
    set_font = Signal(str, int, str)
    set_pos = Signal(str)
    set_opacity = Signal(int)

    def __init__(self, app, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.app = app
        self.settings = Settings()

        # 最外层垂直布局
        layout = QVBoxLayout()

        # 窗口设置组
        group_box_window = QGroupBox('窗口设置')

        # 组内表单布局
        form_layout = QFormLayout()

        # 窗口显示位置设置
        hbox_layout_win_pos = QHBoxLayout()  # 控件水平布局

        self.radio_btn_group_pos = QButtonGroup()
        self.radio_btn_group_pos.addButton(QRadioButton('上', group_box_window), 0)
        self.radio_btn_group_pos.addButton(QRadioButton('下', group_box_window), 1)
        self.radio_btn_group_pos.addButton(QRadioButton('左', group_box_window), 2)
        self.radio_btn_group_pos.addButton(QRadioButton('右', group_box_window), 3)

        for b in self.radio_btn_group_pos.buttons():
            hbox_layout_win_pos.addWidget(b)

        # 窗口透明度设置
        hbox_layout_win_opacity = QHBoxLayout()  # 控件水平布局

        self.slider_opacity = QSlider(Qt.Orientation.Horizontal, self)
        self.slider_opacity.setMinimum(0)
        self.slider_opacity.setMaximum(255)
        self.slider_opacity.setValue(self.settings.opacity)
        self.slider_opacity.valueChanged.connect(self.on_slider_opacity_value_changed)

        self.label_opacity = QLabel(str(self.settings.opacity))

        hbox_layout_win_opacity.addWidget(self.slider_opacity)
        hbox_layout_win_opacity.addWidget(self.label_opacity)

        # 表格布局
        form_layout.addRow(QLabel('显示位置'), hbox_layout_win_pos)
        form_layout.addRow(QLabel('透明度'), hbox_layout_win_opacity)
        group_box_window.setLayout(form_layout)

        layout.addWidget(group_box_window)

        # 文本框组框
        group_box_font = QGroupBox('文本设置')
        form_layout = QFormLayout()

        # 字体设置
        font_families = QFontDatabase.families()  # 系统字体
        self.cmb_font_family = QComboBox()
        self.cmb_font_family.setEditable(True)  # 可编辑
        self.cmb_font_family.addItems(font_families)  # 添加字体
        self.cmb_font_family.setCurrentText(self.settings.font_family)

        # 字号设置
        self.spb_font_size = QSpinBox()
        self.spb_font_size.setMinimum(8)
        self.spb_font_size.setMaximum(32)
        self.spb_font_size.setValue(self.settings.font_size)

        # 字体颜色设置
        self.btn_font_color = QPushButton('设置颜色', self)
        self.btn_font_color.clicked.connect(self.on_btn_font_color_clicked)
        self.btn_font_color.setStyleSheet(f"color: {self.settings.font_color}")

        # 表格布局
        form_layout.addRow(QLabel('字体'), self.cmb_font_family)
        form_layout.addRow(QLabel('字号'), self.spb_font_size)
        form_layout.addRow(QLabel('颜色'), self.btn_font_color)
        group_box_font.setLayout(form_layout)

        layout.addWidget(group_box_font)

        self.setLayout(layout)

        # 初始化
        self.pos = self.settings.pos
        self.opacity = self.settings.opacity
        self.font_family = self.settings.font_family
        self.font_size = self.settings.font_size
        self.font_color = self.settings.font_color

    def connect_slots(self):
        self.set_pos.connect(self.app.main_window.set_pos_handler)
        self.set_opacity.connect(self.app.main_window.set_opacity_handler)
        self.set_font.connect(self.app.main_window.set_font_handler)

    @property
    def pos(self) -> str:
        checked_id = self.radio_btn_group_pos.checkedId()
        pos_query = {
            0: 'up',
            1: 'down',
            2: 'left',
            3: 'right'
        }
        pos = self.settings.pos

        try:
            pos = pos_query[checked_id]
        except IndexError:
            logger.exception(f'Invalid position settings, checked_id={checked_id}')
        finally:
            return pos

    @pos.setter
    def pos(self, value: str):
        pos_query = {
            'up': 0,
            'down': 1,
            'left': 2,
            'right': 3,
        }
        try:
            checked_id = pos_query[value]
            self.radio_btn_group_pos.button(checked_id).setChecked(True)
        except KeyError:
            logger.exception(f'Invalid position, pos={value}')

    @property
    def opacity(self) -> int:
        return self.slider_opacity.value()

    @opacity.setter
    def opacity(self, value: int):
        self.slider_opacity.setValue(value)

    @property
    def font_family(self) -> str:
        return self.cmb_font_family.currentText()

    @font_family.setter
    def font_family(self, value: str):
        self.cmb_font_family.setCurrentText(value)

    @property
    def font_size(self) -> int:
        return self.spb_font_size.value()

    @font_size.setter
    def font_size(self, value: int):
        self.spb_font_size.setValue(value)

    @property
    def font_color(self) -> str:
        return self.btn_font_color.palette().color(QPalette.ButtonText).name()

    @font_color.setter
    def font_color(self, value: str):
        self.btn_font_color.setStyleSheet(f"color: {value}")

    def save_settings(self):
        self.settings.pos = self.pos
        self.settings.opacity = self.opacity
        self.settings.font_family = self.font_family
        self.settings.font_size = self.font_size
        self.settings.font_color = self.font_color

        self.set_pos.emit(self.settings.pos)
        self.set_opacity.emit(self.settings.opacity)
        self.set_font.emit(self.settings.font_family, self.settings.font_size, self.settings.font_color)

        logger.debug('Return')

    @Slot(str)
    def set_pos_handler(self, pos):
        logger.debug(f'Handle set_pos, pos={pos}')
        self.pos = pos

    def on_btn_font_color_clicked(self):
        color = QColorDialog.getColor()
        if color.isValid():
            self.btn_font_color.setStyleSheet(f'color: {color.name()}')

    def on_slider_opacity_value_changed(self):
        opacity = self.slider_opacity.value()
        self.label_opacity.setText(str(opacity))


class TransAPITab(QWidget):

    def __init__(self, app, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.app = app
        self.settings = Settings()

        # 最外层垂直布局
        vbox_layout = QVBoxLayout()

        # 百度翻译 API 设置组
        group_box_baidu = QGroupBox('百度翻译')

        # 表单布局
        form_layout = QFormLayout()

        self.line_edit_baidu_app_id = QLineEdit()
        self.line_edit_baidu_secret_key = QLineEdit()

        form_layout.addRow(QLabel('APP ID'), self.line_edit_baidu_app_id)
        form_layout.addRow(QLabel('密钥'), self.line_edit_baidu_secret_key)

        group_box_baidu.setLayout(form_layout)
        vbox_layout.addWidget(group_box_baidu)

        # 有道翻译 API 设置组
        group_box_youdao = QGroupBox('有道智云')
        form_layout = QFormLayout()

        self.line_edit_youdao_app_id = QLineEdit()
        self.line_edit_youdao_secret_key = QLineEdit()

        form_layout.addRow(QLabel('应用 ID'), self.line_edit_youdao_app_id)
        form_layout.addRow(QLabel('应用密钥'), self.line_edit_youdao_secret_key)

        self.btn_group_youdao_domain = QButtonGroup()
        self.btn_group_youdao_domain.addButton(QRadioButton('通用（默认）', group_box_youdao), 0)
        self.btn_group_youdao_domain.addButton(QRadioButton('计算机', group_box_youdao), 1)
        self.btn_group_youdao_domain.addButton(QRadioButton('医学', group_box_youdao), 2)

        hbox = QHBoxLayout()
        for b in self.btn_group_youdao_domain.buttons():
            hbox.addWidget(b)
        form_layout.addRow(QLabel('领域化翻译'), hbox)

        self.checkbox_youdao_reject_fallback = QCheckBox('拒绝领域化翻译降级')
        self.checkbox_youdao_reject_fallback.setToolTip('当领域化翻译失败时改为通用翻译')
        form_layout.addRow(QLabel(''), self.checkbox_youdao_reject_fallback)

        # 按钮点击事件，设置是否可以设置领域化翻译降级
        self.btn_group_youdao_domain.button(0).clicked.connect(
            lambda: self.checkbox_youdao_reject_fallback.setEnabled(False))
        self.btn_group_youdao_domain.button(1).clicked.connect(
            lambda: self.checkbox_youdao_reject_fallback.setEnabled(True))
        self.btn_group_youdao_domain.button(2).clicked.connect(
            lambda: self.checkbox_youdao_reject_fallback.setEnabled(True))

        group_box_youdao.setLayout(form_layout)
        vbox_layout.addWidget(group_box_youdao)

        self.setLayout(vbox_layout)

        # 初始化
        self.baidu_app_id = self.settings.baidu_app_id
        self.baidu_secret_key = self.settings.baidu_secret_key

        self.youdao_app_id = self.settings.youdao_app_id
        self.youdao_secret_key = self.settings.youdao_secret_key
        self.youdao_domain = self.settings.youdao_domain
        self.youdao_reject_fallback = self.settings.youdao_reject_fallback

    @property
    def baidu_app_id(self) -> str:
        return self.line_edit_baidu_app_id.text()

    @baidu_app_id.setter
    def baidu_app_id(self, value: str):
        self.line_edit_baidu_app_id.setText(value)

    @property
    def baidu_secret_key(self) -> str:
        return self.line_edit_baidu_secret_key.text()

    @baidu_secret_key.setter
    def baidu_secret_key(self, value: str):
        self.line_edit_baidu_secret_key.setText(value)

    @property
    def youdao_app_id(self) -> str:
        return self.line_edit_youdao_app_id.text()

    @youdao_app_id.setter
    def youdao_app_id(self, value: str):
        self.line_edit_youdao_app_id.setText(value)

    @property
    def youdao_secret_key(self) -> str:
        return self.line_edit_youdao_secret_key.text()

    @youdao_secret_key.setter
    def youdao_secret_key(self, value: str):
        self.line_edit_youdao_secret_key.setText(value)

    @property
    def youdao_domain(self) -> str:
        checked_id = self.btn_group_youdao_domain.checkedId()
        domain_query = {
            0: 'general',
            1: 'computers',
            2: 'medicine'
        }
        domain = self.settings.youdao_domain

        try:
            domain = domain_query[checked_id]
        except IndexError:
            logger.exception(f'Invalid domain, checked_id={checked_id}')
        finally:
            return domain

    @youdao_domain.setter
    def youdao_domain(self, value: str):
        domain_query = {
            'general': 0,
            'computers': 1,
            'medicine': 2
        }

        try:
            index = domain_query[value]
            self.btn_group_youdao_domain.button(index).setChecked(True)
        except KeyError:
            logger.exception(f'Invalid domain, value={value}')

    @property
    def youdao_reject_fallback(self) -> bool:
        return self.checkbox_youdao_reject_fallback.isChecked()

    @youdao_reject_fallback.setter
    def youdao_reject_fallback(self, value: bool):
        self.checkbox_youdao_reject_fallback.setChecked(value)

    def save_settings(self):
        self.settings.baidu_app_id = self.baidu_app_id
        self.settings.baidu_secret_key = self.baidu_secret_key

        self.settings.youdao_app_id = self.youdao_app_id
        self.settings.youdao_secret_key = self.youdao_secret_key
        self.settings.youdao_domain = self.youdao_domain
        self.settings.youdao_reject_fallback = self.youdao_reject_fallback
